package com.ruoyi.web.controller.common;

import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.annotation.Anonymous;

/**
 * 微信相关请求处理
 * 
 * @author ruoyi
 */
@RestController
@RequestMapping("/wx")
public class WxController {
    @Autowired
    private ISysUserService userService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysPermissionService permissionService;

    @Value("${wechat.appid}")
    private String appid;

    @Value("${wechat.secret}")
    private String secret;

    /**
     * 获取openid
     */
    @Anonymous
    @GetMapping("/bind-openid")
    public void getOpenid(@RequestParam("code") String code, @RequestParam("key") String key,
            HttpServletResponse response) throws IOException {
        // 1. 根据微信返回的 code 换取 openid 和昵称
        SysUser u = userService.getOpenid(code);
        String openid = u.getOpenid();
        // 2. 查询是否已有用户绑定该 openid
        SysUser existUser = userService.selectUserByOpenId(openid);
        if (existUser != null) {
            response.setContentType("text/html;charset=UTF-8");
            String errorHtml = "<!DOCTYPE html>" +
                    "<html lang='zh'>" +
                    "<head>" +
                    "    <meta charset='UTF-8'>" +
                    "    <meta name='viewport' content='width=device-width, initial-scale=1.0'>" +
                    "    <title>绑定失败</title>" +
                    "    <style>" +
                    "        body { margin: 0; padding: 0; display: flex; align-items: center; justify-content: center; height: 100vh; background: #fff1f0; font-family: Arial, sans-serif; }"
                    +
                    "        .container { text-align: center; }" +
                    "        .message { font-size: 20px; color: #cf1322; margin-top: 20px; }" +
                    "    </style>" +
                    "</head>" +
                    "<body>" +
                    "    <div class='container'>" +
                    "        <div class='message'>该微信已绑定其他账号，无法重复绑定。</div>" +
                    "    </div>" +
                    "    <script>" +
                    "        setTimeout(function () {" +
                    "            if (typeof WeixinJSBridge !== 'undefined') {" +
                    "                WeixinJSBridge.call('closeWindow');" +
                    "            }" +
                    "        }, 3000);" +
                    "    </script>" +
                    "</body>" +
                    "</html>";
            response.getWriter().write(errorHtml);
            return;
        }

        // 3. 从缓存中获取当前登录用户
        LoginUser userCache = redisCache.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + key);
        SysUser user = new SysUser();
        user.setUserId(userCache.getUserId());
        user.setOpenid(openid);
        user.setWxNickName(u.getWxNickName());
        // 4. 绑定 openid
        userService.updateUserOpenid(user);

        // 更新Redis缓存中的用户信息
        SysUser updatedUser = userService.selectUserById(userCache.getUserId());
        userCache.setUser(updatedUser);
        redisCache.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + key, userCache);

        // 添加绑定标记
        String bindKey = "wx_binding:" + userCache.getUserId();
        redisCache.setCacheObject(bindKey, true, 5, TimeUnit.MINUTES);

        response.setContentType("text/html;charset=UTF-8");
        String html = "<!DOCTYPE html>" +
                "<html lang='zh'>" +
                "<head>" +
                "    <meta charset='UTF-8'>" +
                "    <meta name='viewport' content='width=device-width, initial-scale=1.0'>" +
                "    <title>绑定成功</title>" +
                "    <style>" +
                "        body { margin: 0; padding: 0; display: flex; align-items: center; justify-content: center; height: 100vh; background: #f0f2f5; font-family: Arial, sans-serif; }"
                +
                "        .container { text-align: center; }" +
                "        .message { font-size: 20px; color: #333; margin-top: 20px; animation: fadeIn 1s ease-in-out; }"
                +
                "        .loader {" +
                "            border: 4px solid #f3f3f3;" +
                "            border-top: 4px solid #3498db;" +
                "            border-radius: 50%;" +
                "            width: 40px;" +
                "            height: 40px;" +
                "            animation: spin 1s linear infinite;" +
                "            margin: 0 auto;" +
                "        }" +
                "        @keyframes spin {" +
                "            0% { transform: rotate(0deg); }" +
                "            100% { transform: rotate(360deg); }" +
                "        }" +
                "        @keyframes fadeIn {" +
                "            from { opacity: 0; }" +
                "            to { opacity: 1; }" +
                "        }" +
                "    </style>" +
                "</head>" +
                "<body>" +
                "    <div class='container'>" +
                "        <div class='loader'></div>" +
                "        <div class='message'>绑定成功，正在关闭页面...</div>" +
                "    </div>" +
                "    <script>" +
                "        setTimeout(function () {" +
                "            if (typeof WeixinJSBridge !== 'undefined') {" +
                "                WeixinJSBridge.call('closeWindow');" +
                "            }" +
                "        }, 1500);" +
                "    </script>" +
                "</body>" +
                "</html>";

        response.getWriter().write(html);
    }

    /**
     * 已登录用户uuid查询openid
     */
    @GetMapping("/uuid")
    public AjaxResult getCode(@RequestParam("uuid") String uuid) throws IOException {
        AjaxResult ajax = AjaxResult.success();
        LoginUser userLogin = redisCache.getCacheObject(CacheConstants.LOGIN_TOKEN_KEY + uuid);

        // 始终从数据库获取最新的用户信息
        SysUser user = userService.selectUserById(userLogin.getUserId());

        // 更新缓存中的用户信息
        userLogin.setUser(user);
        redisCache.setCacheObject(CacheConstants.LOGIN_TOKEN_KEY + uuid, userLogin);

        System.out.println("user-openid: " + user.getOpenid());
        System.out.println("user-wxnickname: " + user.getWxNickName());
        if (user.getOpenid() != null) {
            ajax.put("openid", user.getOpenid());
            ajax.put("wxnickname", user.getWxNickName());
        }

        // 只有当wxBind方法已经调用bind-openid接口且更新了用户的openid后，这里的status才会返回1
        // 通过检查请求中是否存在特定标记来决定是查询状态还是等待绑定
        String bindKey = "wx_binding:" + userLogin.getUserId();
        Boolean isBiding = redisCache.getCacheObject(bindKey);
        if (isBiding != null && isBiding && user.getOpenid() != null) {
            ajax.put("status", 1);
            // 绑定成功后清除标记
            redisCache.deleteObject(bindKey);
        } else {
            ajax.put("status", 0);
        }
        return ajax;
    }

    /**
     * 扫码登录用uuid生成
     */
    @Anonymous
    @GetMapping("/uuid/get")
    public AjaxResult getUUID() throws IOException {
        AjaxResult ajax = AjaxResult.success();
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
        redisCache.setCacheObject(verifyKey, null, 1, TimeUnit.MINUTES);
        ajax.put("uuid", uuid);
        return ajax;
    }

    /**
     * uuid绑定openid
     */
    @Anonymous
    @GetMapping("/uuid/bind/openid")
    public AjaxResult bindOpenid(@RequestParam("code") String code, @RequestParam("state") String uuid)
            throws IOException {
        AjaxResult ajax = AjaxResult.success();
        SysUser user = userService.getOpenid(code);
        String openid = user.getOpenid();
        String wxNickName = user.getWxNickName();
        String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
        long expire = redisCache.getExpire(verifyKey);
        redisCache.setCacheObject(verifyKey, openid);
        if (expire > 0) {
            redisCache.expire(verifyKey, expire, TimeUnit.SECONDS);
        }
        ajax.put("openid", openid);
        ajax.put("wxNickName", wxNickName);
        return ajax;
    }

    /**
     * uuid登录
     */
    @Anonymous
    @GetMapping("/uuid/login")
    public AjaxResult loginByOpenId(@RequestParam("uuid") String uuid) throws IOException {
        AjaxResult ajax = AjaxResult.success();
        String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
        String openid = redisCache.getCacheObject(verifyKey);
        ajax.put("status", 0);
        System.out.println("openid：{}" + openid);
        if (openid != null) {
            SysUser user = userService.selectUserByOpenId(openid);
            System.out.println("用户：{}" + user);
            if (user == null) {
                System.out.println("用户不存在");
                return AjaxResult.error("用户不存在");
            }
            LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user,
                    permissionService.getMenuPermission(user));
            // 生成token
            String token = tokenService.createToken(loginUser);
            ajax.put("token", token);
            ajax.put("status", 1);
            redisCache.deleteObject(verifyKey);
        }

        return ajax;
    }

    /**
     * 生成微信绑定二维码图片
     * 使用代理方式隐藏appid
     */
    @Anonymous
    @GetMapping("/qr-bindImg")
    public void generateQrBindImage(@RequestParam("key") String key, HttpServletRequest request,
            HttpServletResponse response) throws IOException, WriterException {
        // 1.查询二维码跳转URL(可缓存或直接生成)
        String qrContent = getRealBindQrUrl(key, request);// 比如调用微信API获取扫码登录二维码

        // 2.设置响应头
        response.setContentType("image/png");

        // 3.生成二维码图像并写入相应流
        int width = 280;
        int height = 280;
        BitMatrix bitMatrix = new MultiFormatWriter().encode(qrContent, BarcodeFormat.QR_CODE, width, height);
        try (OutputStream os = response.getOutputStream()) {
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", os);
        }
    }

    /**
     * 微信绑定代理接口
     * 用于隐藏appid
     */
    @Anonymous
    @GetMapping("/proxy-bind")
    public void proxyBind(@RequestParam("key") String key, HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        // 使用固定域名，不带端口号
        String redirectUri = "http://l9ahqakkef0e.vip3.xiaomiqiu123.top/wx/bind-openid?key=" + key;
        String encodedRedirectUri = URLEncoder.encode(redirectUri, String.valueOf(StandardCharsets.UTF_8));
        String wechatAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"
                + "?appid=" + appid
                + "&redirect_uri=" + encodedRedirectUri
                + "&response_type=code"
                + "&scope=snsapi_userinfo"
                + "&state=STATE#wechat_redirect";

        response.sendRedirect(wechatAuthUrl);
    }

    /**
     * 获取真实的微信绑定URL
     */
    private String getRealBindQrUrl(String key, HttpServletRequest request) {
        // 返回自己的后端跳转地址，而不是微信链接
        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                + "/wx/proxy-bind?key=" + key;
    }

    /**
     * 生成扫码登录二维码图片
     */
    @Anonymous
    @GetMapping("/qr-img")
    public void generateQrImage(@RequestParam("uuid") String uuid, HttpServletRequest request,
            HttpServletResponse response) throws IOException, WriterException {
        // 1.查询二维码跳转URL(可缓存或直接生成)
        String qrContent = getRealQrUrl(uuid, request);

        // 2.设置响应头
        response.setContentType("image/png");

        // 3.生成二维码图像并写入相应流
        int width = 280;
        int height = 280;
        BitMatrix bitMatrix = new MultiFormatWriter().encode(qrContent, BarcodeFormat.QR_CODE, width, height);
        try (OutputStream os = response.getOutputStream()) {
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", os);
        }
        System.out.println("二维码");
    }

    /**
     * 获取真实的扫码登录URL
     */
    private String getRealQrUrl(String uuid, HttpServletRequest request) {
        // 返回自己的后端跳转地址，而不是微信链接
        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                + "/wx/proxy-login?uuid=" + uuid;
    }

    /**
     * 微信登录代理接口
     * 用于隐藏appid
     */
    @Anonymous
    @GetMapping("/proxy-login")
    public void proxyLogin(@RequestParam("uuid") String uuid, HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        // 为了使用state传递uuid，同时避免和微信的state参数冲突，这里将uuid作为state值的一部分
        String state = "uuid=" + uuid + "&path=wx/uuid/bind/openid/ui";
        String redirectUri = "http://l9ahqakkef0e.vip3.xiaomiqiu123.top/wx/uuid/bind/openid/ui?uuid=" + uuid;
        String encodedRedirectUri = URLEncoder.encode(redirectUri, String.valueOf(StandardCharsets.UTF_8));
        String wechatAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"
                + "?appid=" + appid
                + "&redirect_uri=" + encodedRedirectUri
                + "&response_type=code"
                + "&scope=snsapi_userinfo"
                + "&state=" + state + "#wechat_redirect";

        response.sendRedirect(wechatAuthUrl);
    }

    /**
     * uuid绑定openid，并显示成功页面
     */
    @Anonymous
    @GetMapping("/uuid/bind/openid/ui")
    public void bindOpenidWithUI(@RequestParam("code") String code, @RequestParam("uuid") String uuid,
            HttpServletResponse response) throws IOException {
        SysUser user = userService.getOpenid(code);
        String openid = user.getOpenid();
        String wxNickName = user.getWxNickName();
        String verifyKey = CacheConstants.WX_OPENID_KEY + uuid;
        long expire = redisCache.getExpire(verifyKey);
        redisCache.setCacheObject(verifyKey, openid);
        if (expire > 0) {
            redisCache.expire(verifyKey, expire, TimeUnit.SECONDS);
        }

        response.setContentType("text/html;charset=UTF-8");
        String html = "<!DOCTYPE html>" +
                "<html lang='zh'>" +
                "<head>" +
                "    <meta charset='UTF-8'>" +
                "    <meta name='viewport' content='width=device-width, initial-scale=1.0'>" +
                "    <title>登录成功</title>" +
                "    <style>" +
                "        body { margin: 0; padding: 0; display: flex; align-items: center; justify-content: center; height: 100vh; background: #f0f2f5; font-family: Arial, sans-serif; }"
                +
                "        .container { text-align: center; }" +
                "        .message { font-size: 20px; color: #333; margin-top: 20px; animation: fadeIn 1s ease-in-out; }"
                +
                "        .loader {" +
                "            border: 4px solid #f3f3f3;" +
                "            border-top: 4px solid #3498db;" +
                "            border-radius: 50%;" +
                "            width: 40px;" +
                "            height: 40px;" +
                "            animation: spin 1s linear infinite;" +
                "            margin: 0 auto;" +
                "        }" +
                "        @keyframes spin {" +
                "            0% { transform: rotate(0deg); }" +
                "            100% { transform: rotate(360deg); }" +
                "        }" +
                "        @keyframes fadeIn {" +
                "            from { opacity: 0; }" +
                "            to { opacity: 1; }" +
                "        }" +
                "    </style>" +
                "</head>" +
                "<body>" +
                "    <div class='container'>" +
                "        <div class='loader'></div>" +
                "        <div class='message'>登录成功，正在关闭页面...</div>" +
                "    </div>" +
                "    <script>" +
                "        setTimeout(function () {" +
                "            if (typeof WeixinJSBridge !== 'undefined') {" +
                "                WeixinJSBridge.call('closeWindow');" +
                "            }" +
                "        }, 1500);" +
                "    </script>" +
                "</body>" +
                "</html>";

        response.getWriter().write(html);
    }
}